/*
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * RSTriangles.cpp
 *
 *  Created on: 2010/02/27
 *      Author: Alexandre Pires ( c.alexandre.pires@gmail.com )
 */

#include "RSTriangles.h"
#include "RSInput.h"
#include "RSPrimitiveIndices.h"

namespace Realsphere {

    RSTriangles::RSTriangles ( const QString& rName ) :
        RSPrimitivesElement ( RS_TRIANGLES, rName )
    {
        mPrimitiveIndices = NULL;
    }

    RSTriangles::~RSTriangles ()
    {
        mPrimitiveIndices = NULL;
    }

    unsigned int RSTriangles::Count () const
    {
        if ( mPrimitiveIndices != NULL )
            return mPrimitiveIndices->Count ();

        return 0;
    }

    RSPrimitiveIndices* RSTriangles::PrimitiveIndices () const
    {
        return mPrimitiveIndices;
    }

    RSInput* RSTriangles::GetInput ( unsigned int rIndex ) const
    {
        return mInputs[rIndex];
    }

    RSInputs RSTriangles::Inputs () const
    {
        return mInputs;
    }

    int RSTriangles::IndexOf ( RSInput* rInput )
    {
        return mInputs.indexOf ( rInput );
    }

    unsigned int RSTriangles::InputsSize ()
    {
        return mInputs.size ();
    }

    RSInputs RSTriangles::Inputs ( RSInputSemanticType rSemanticType ) const
    {
        RSInputs inputs;
        RSInputsIterator iterator = RSInputsIterator ( mInputs );

        while ( iterator.hasNext () )
        {
            RSInput* input = iterator.next ();

            if ( input->SemanticType () == rSemanticType )
                inputs.append ( input );
        }

        return inputs;
    }

    RSInputsIterator RSTriangles::InputsIterator () const
    {
        return RSInputsIterator ( mInputs );
    }

    RSInputsIterator RSTriangles::InputsIterator (
            RSInputSemanticType rSemanticType ) const
    {
        RSInputs inputs = Inputs ( rSemanticType );
        return RSInputsIterator ( inputs );
    }

    bool RSTriangles::IsRootElement () const
    {
        return false;
    }

    RSError RSTriangles::BeforeAddChildElement ( RSElement* rChild )
    {
        RSError error = RSElement::BeforeAddChildElement ( rChild );

        if ( error == RS_INVALID_ELEMENT )
        {
            if ( rChild->InstanceOf ( RS_INPUT_CLASS ) )
            {
                RSInput* input = RSInputCast ( rChild );
                RSInputsIterator iterator = InputsIterator (
                        input->SemanticType () );

                error = RS_NO_ERROR;

                while ( iterator.hasNext () )
                {
                    RSInput* current_input = iterator.next ();

                    if ( current_input->Set () == input->Set () )
                        error = RS_INPUT_SET_ALREADY_EXIST;
                }
            }
            else if ( rChild->InstanceOf ( RS_PRIMITIVE_INDICES_CLASS ) )
            {
                if ( mPrimitiveIndices != NULL )
                    RemoveChildElement ( mPrimitiveIndices );

                mPrimitiveIndices = NULL;

                error = RS_NO_ERROR;
            }
        }

        return error;
    }

    bool RSTriangles::AfterAddChildElement ( RSElement* rChild )
    {
        bool handled = RSElement::AfterAddChildElement ( rChild );

        if ( !handled )
        {
            if ( rChild->InstanceOf ( RS_INPUT_CLASS ) )
            {
                RSInput* input = RSInputCast ( rChild );
                mInputs.append ( input );
                handled = true;

                emit InputAdded ( input );
            }
            else if ( rChild->InstanceOf ( RS_PRIMITIVE_INDICES_CLASS ) )
            {
                RSPrimitiveIndices* primitive_indices =
                        RSPrimitiveIndicesCast ( rChild );
                mPrimitiveIndices = primitive_indices;
                handled = true;

                emit PrimitiveIndicesChanged ( primitive_indices );
            }
        }

        return handled;
    }

    bool RSTriangles::AfterRemoveChildElement ( RSElement* rChild )
    {
        bool handled = RSElement::AfterRemoveChildElement ( rChild );

        if ( !handled )
        {

            if ( rChild->InstanceOf ( RS_INPUT_CLASS ) )
            {
                RSInput* input = RSInputCast ( rChild );
                int input_index = mInputs.indexOf ( input );
                mInputs.removeAt ( input_index );
                handled = true;

                emit InputRemoved ( input );
            }
            else if ( rChild->InstanceOf ( RS_PRIMITIVE_INDICES_CLASS ) )
            {

                RSPrimitiveIndices* primitive_indices =
                        RSPrimitiveIndicesCast ( rChild );
                mPrimitiveIndices = NULL;
                handled = true;

                emit PrimitiveIndicesChanged ( primitive_indices );
            }
        }

        return handled;
    }

    RSError RSTriangles::AddInput ( RSInput* rInput )
    {
        RSError error = AddChildElement ( rInput );
        return error;
    }

    RSError RSTriangles::RemoveInput ( RSInput* rInput )
    {
        RSError error = RemoveChildElement ( rInput );
        return error;
    }

    RSError RSTriangles::RemoveInput ( unsigned int rIndex )
    {
        RSInput* input = mInputs[rIndex];
        RSError error = RemoveInput ( input );
        return error;
    }

    RSError RSTriangles::RemoveInputs ( RSInputSemanticType rSemanticType )
    {
        RSInputsIterator iterator = InputsIterator ( rSemanticType );
        RSError error = RS_NO_ERROR;

        while ( iterator.hasNext () )
        {
            RSInput* current_input = iterator.next ();
            error = RemoveInput ( current_input );

            if ( error )
                break;
        }

        return error;
    }

    RSError RSTriangles::SetPrimitiveIndices (
            RSPrimitiveIndices* rPrimitiveIndices )
    {
        RSError error = AddChildElement ( rPrimitiveIndices );
        return error;
    }
}
